from django.core.urlresolvers import reverse
from datetime import date, timedelta
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.views.generic.list_detail import object_list

from projects.forms import *
from projects.models import *

from tagging.models import TaggedItem

import vobject

try:
  from notification import models as notification
except ImportError:
  notification = None

def deliverableSetComplete(request, deliverable_id):
  deliverable = get_object_or_404(Deliverable, id=deliverable_id)
  if request.POST['status'] == "complete":
    deliverable.completed_date = date.today()
    if notification:
      notification.send(User.objects.filter(id=1), "deliverable_complete", {"deliverable": deliverable })
    else:
      return HttpResponse(content="Notifications are not configured on this server. Please contact your Systems Administrator.", status=501)
  else:
    deliverable.completed_date = None
    if notification:
      notification.send(User.objects.filter(id=1), "deliverable_incomplete", {"deliverable": deliverable })
    else:
      return HttpResponse(content="Notifications are not configured on this server. Please contact your Systems Administrator.", status=501)
  deliverable.save()
  return HttpResponseRedirect(request.META.get('HTTP_REFERER', ''))
  
def requestTaskUpdate(request, task_id):
    '''
    Set a notification to the owner of a task asking for an update on the objects status.
    '''
    task = get_object_or_404(Task, id=task_id)
    if notification:
      notification.send(User.objects.filter(id=task.lead.id), "request_task_update", {"task": task, "requestor": request.user})
    else:
      return HttpResponse(content="Notifications are not configured on this server. Please contact your Systems Administrator.", status=501)
    return HttpResponseRedirect(request.META.get('HTTP_REFERER', ''))

def requestDeliverableUpdate(request, deliverable_id):
    '''
    Set a notification to the owner of a deliverable asking for an update on the objects status.
    '''
    deliverable = get_object_or_404(Deliverable, id=deliverable_id)
    if notification:
      notification.send(User.objects.filter(id=deliverable.owner.id), "request_deliverable_update", {"deliverable": deliverable, "requestor": request.user})
    else:
      return HttpResponse(content="Notifications are not configured on this server. Please contact your Systems Administrator.", status=501)
    return HttpResponseRedirect(request.META.get('HTTP_REFERER', ''))

def incomplete_deliverable_list(request):
  deliverables = Deliverable.objects.filter(completed_date = None).order_by('target_date', 'start_date')
  return object_list(request, queryset=deliverables)

def taskSetComplete(request, task_id):
  task = get_object_or_404(Task, id=task_id)
  if request.POST['status'] == "complete":
    task.completed_date = date.today()
    if notification:
      notification.send(User.objects.filter(id=1), "task_complete", {"task": task })
    else:
      return HttpResponse(content="Notifications are not configured on this server. Please contact your Systems Administrator.", status=501)
  else:
    task.completed_date = None
    if notification:
      notification.send(User.objects.filter(id=1), "task_incomplete", {"task": task })
    else:
      return HttpResponse(content="Notifications are not configured on this server. Please contact your Systems Administrator.", status=501)
  task.save()
  return HttpResponseRedirect(request.META.get('HTTP_REFERER', ''))

def incomplete_task_list(request, deliverable_id=None):
  if (deliverable_id):
    tasks = Task.objects.filter(completed_date = None)
  else:
    tasks = Task.objects.filter(completed_date = None).order_by('target_date', 'start_date')
  return object_list(request, queryset=tasks)

def task_form(request, task_id=None, parent_id=None, deliverable_id=None, objective_id=None):
  if task_id:
    task = get_object_or_404(Task, id=task_id)
    isNew = False
  else:
    task = Task()
    isNew = True

  if parent_id:
    parentTask = get_object_or_404(Task, id=parent_id)
    task.parent = parentTask
    task.start_date = parentTask.start_date

  if deliverable_id:
    deliverable = get_object_or_404(Deliverable, id=deliverable_id)    
    task.target_date = deliverable.target_date
    task.start_date = deliverable.start_date

  if objective_id:
    objective = get_object_or_404(Objective, id=objective_id)    
    task.target_date = objective.target_date
    task.start_date = objective.start_date
      
  if request.POST:    
    form = TaskForm(data=request.POST, instance=task)
    configure_task_form(form)

    if form.is_valid():
      form.save()
      if notification and isNew:
        notification.send(User.objects.filter(id=1), "task_created", {"task": task, "queue": True })
      if notification and not isNew:
        notification.send(User.objects.filter(id=1), "task_updated", {"task": task, "queue": True })
      if deliverable_id:
        deliverable.task.add(task)
      if objective_id:
        objective.task.add(task)
      return HttpResponseRedirect(reverse('task_detail', args=(task.id,)))
    else:
      request.user.message_set.create(message='Please check your data.')
  else:
    form = TaskForm(instance=task)
    configure_task_form(form)

  return render_to_response('task_form.html', {'form':form}, context_instance=RequestContext(request))

def configure_task_form(form):
  form.fields['parent'].queryset = Task.objects.filter(completed_date = None)  

def tagged_task(request, tag_name=None):
  tasks = TaggedItem.objects.get_by_model(Task, tag_name)
  return object_list(request, queryset=tasks)

def deliverable_form(request, deliverable_id=None, objective_id=None):
  if deliverable_id:
    deliverable = get_object_or_404(Deliverable, id=deliverable_id)
    isNew = False
  else:
    deliverable = Deliverable()
    isNew = True

  if objective_id:
    objective = get_object_or_404(Objective, id=objective_id)
    deliverable.objective = objective
    deliverable.target_date = objective.target_date

  if request.POST:    
    form = DeliverableForm(data=request.POST, instance=deliverable)

    if form.is_valid():
      form.save()
      if notification and isNew:
          notification.send(User.objects.filter(id=1), "deliverable_created", {"deliverable": deliverable })
      if notification and not isNew:
          notification.send(User.objects.filter(id=1), "deliverable_updated", {"deliverable": deliverable })
      return HttpResponseRedirect(reverse('deliverable_detail', args=(deliverable.id,)))
    else:
      request.user.message_set.create(message='Please check your data.')
  else:
    form = DeliverableForm(instance=deliverable)

  return render_to_response('task_form.html', {'form':form}, context_instance=RequestContext(request))

def aim_form(request, aim_id=None, wp_id=None):
  ''' Edit an existing aim (if aim_id is set to the id of an existing object) or add a new aim
      to the work package identified by wp_id
  '''
  if aim_id:
    aim = get_object_or_404(Aim, id=aim_id)
    isNew = False
  else:
    aim = Aim()
    isNew = True

  if wp_id:
    wp = get_object_or_404(WorkPackage, id=wp_id)
    aim.work_package = wp

  if request.POST:    
    form = AimForm(data=request.POST, instance=aim)

    if form.is_valid():
      form.save()
      if notification and isNew:
          notification.send(User.objects.filter(id=1), "aim_created", {"aim": aim })
      if notification and not isNew:
          notification.send(User.objects.filter(id=1), "aim_updated", {"aim": aim })
      return HttpResponseRedirect(reverse('aim_detail', args=(aim.id,)))
    else:
      request.user.message_set.create(message='Please check your data.')
  else:
    form = AimForm(instance=aim)

  return render_to_response('task_form.html', {'form':form}, context_instance=RequestContext(request))

def work_package_form(request, wp_id=None, project_id=None):
  ''' Edit an existing work package (if wp_id is set to the id of an existing object) or add a new work package
      to the project identified by project_id
  '''
  if wp_id:
    wp = get_object_or_404(WorkPakckage, id=wp_id)
    isNew = False
  else:
    wp = WorkPackage()
    isNew = True

  if project_id:
    project = get_object_or_404(Project, id=project_id)
    wp.project = project

  if request.POST:    
    form = ObjectiveForm(data=request.POST, instance=wp)

    if form.is_valid():
      form.save()
      if notification and isNew:
          notification.send(User.objects.filter(id=1), "work_pacakge_created", {"work_package": wp })
      if notification and not isNew:
          notification.send(User.objects.filter(id=1), "work_package_updated", {"work_package": wp })
      return HttpResponseRedirect(reverse('work_package_detail', args=(wp.id,)))
    else:
      request.user.message_set.create(message='Please check your data.')
  else:
    form = WorkPackageForm(instance=wp)

  return render_to_response('task_form.html', {'form':form}, context_instance=RequestContext(request))

def project_form(request, project_id=None):
  ''' Edit an existing project (if project_id is set to the id of an existing object) or add a new project
  '''
  if project_id:
    project = get_object_or_404(Project, id=project_id)
    isNew = False
  else:
    project = Project()
    isNew = True

  if request.POST:    
    form = ProjectForm(data=request.POST, instance=project)

    if form.is_valid():
      form.save()
      if notification and isNew:
          notification.send(User.objects.filter(id=1), "project_created", {"project": project, "queue": True })
      if notification and not isNew:
          notification.send(User.objects.filter(id=1), "project_updated", {"project": project, "queue": True })
      return HttpResponseRedirect(reverse('project_detail', args=(project.id,)))
    else:
      request.user.message_set.create(message='Please check your data.')
  else:
    form = ProjectForm(instance=project)

  return render_to_response('task_form.html', {'form':form}, context_instance=RequestContext(request))

def tagged_deliverable(request, tag_name=None):
  deliverables = TaggedItem.objects.get_by_model(Deliverable, tag_name)
  return render_to_response('projects/deliverable_list.html', {'set': deliverables}, context_instance=RequestContext(request))

def objective_form(request, aim_id=None, objective_id=None):
  if objective_id:
    objective = get_object_or_404(Objective, id=objective_id)
  else:
    objective = Objective()

  if aim_id:
    aim = get_object_or_404(Aim, id=aim_id)
    objective.aim = aim
    objective.target_date = objective.target_date

  if request.POST:    
    form = ObjectiveForm(data=request.POST, instance=objective)

    if form.is_valid():
      form.save()
      return HttpResponseRedirect(reverse('objective_detail', args=(objective.id,)))
    else:
      request.user.message_set.create(message='Please check your data.')
  else:
    form = ObjectiveForm(instance=objective)

  return render_to_response('task_form.html', {'form':form}, context_instance=RequestContext(request))

def search_form(request):
    dict = {}
    if request.GET:
	term = request.GET['term']
        exclude_complete = request.GET.has_key('excludeComplete')

        tasks = Task.objects.filter(title__contains = term) | Task.objects.filter(description__contains = term)
        if exclude_complete:
          tasks = tasks.filter(completed_date = None)

        deliverables = Deliverable.objects.filter(title__contains = term) | Deliverable.objects.filter(description__contains = term)
        if exclude_complete:
          deliverables = deliverables.filter(completed_date = None)

        objectives = Objective.objects.filter(title__contains = term) | Objective.objects.filter(description__contains = term)

        aims = Aim.objects.filter(title__contains = term) | Aim.objects.filter(description__contains = term)

        work_packages = WorkPackage.objects.filter(title__contains = term)
        if exclude_complete:
          work_packages = work_packages.filter(end_date__gt = date.today())

        projects = Project.objects.filter(title__contains = term)
        if exclude_complete:
          projects = projects.filter(end_date__gt = date.today())

        dict['search_term'] = term
        if exclude_complete:
          dict['exclude_complete'] = True
        if tasks.count() > 0:
          dict['task_list'] = tasks
        if deliverables.count() > 0:
          dict['deliverable_list'] = deliverables
        if objectives.count() > 0:
          dict['objective_list'] = objectives
        if aims.count() > 0:
          dict['aim_list'] = aims
        if work_packages.count() > 0:
          dict['work_package_list'] = work_packages
        if projects.count() > 0:
          dict['project_list'] = projects

	return render_to_response('project_search.html', dict, context_instance=RequestContext(request))
    else:
        dict['exclude_complete'] = True
	return render_to_response('project_search.html', dict, context_instance=RequestContext(request))

def weekly_report(request):
  '''
  Generate the weekly status report for all projects.
  '''
  dict = {}
  dict['completed_deliverable_list'] = Deliverable.objects.filter(completed_date__lte = date.today()).order_by('target_date', 'start_date')
  dict['objective_list'] = Objective.objects.all()
  return render_to_response('report/weekly.html', dict, context_instance=RequestContext(request))

def person_calendar(request, object_id):
  '''
  Generate an ical feed of a persons deliverables
  '''
  cal = vobject.iCalendar()
  cal.add('method').value = 'PUBLISH'  # IE/Outlook needs this
  
  deliverable_list = Deliverable.objects.filter(owner=object_id)
  for deliverable in deliverable_list:
    entry = cal.add('vevent')
    entry.add('summary').value = deliverable.title
    entry.add('description').value = deliverable.description
    entry.add('dtstart').value = deliverable.start_date
    entry.add('dtend').value = deliverable.target_date  
    
  icalstream = cal.serialize()
  response = HttpResponse(icalstream, mimetype='text/calendar')
  response['Filename'] = 'calendar.ics'  # IE needs this
  response['Content-Disposition'] = 'attachment; filename=calendar.ics'
  return response
  
def person_to_estimate(request, person_id):
    """
    Show all deliverables and tasks assigned to a person but do not have a time estimate.
    """
    person = get_object_or_404(Person, id=person_id)
    deliverables = person.deliverable_set.filter(completed_date = None).filter(estimate = None).order_by("target_date")
    tasks = person.task_set.filter(completed_date = None).filter(estimate = None).order_by("target_date")
    dict = {}
    dict['deliverable_list'] = deliverables
    dict['task_list'] = tasks
    return render_to_response('report/toEstimate.html', dict, context_instance=RequestContext(request))

 
def completed(request, duration = 7):
    """
    Show all deliverables and tasks that have been completed within a defined
    period of time. The default time is seven days.
    """
    td = timedelta(days=duration)
    end_date = date.today() - td
    deliverables = Deliverable.objects.filter(completed_date__gte = end_date).order_by("-completed_date")
    dict = {}
    dict['deliverable_list'] = deliverables
    return render_to_response('report/completed.html', dict, context_instance=RequestContext(request))

